
use actix_web::web;
use diesel::prelude::*;

use crate::{models::{self}, ip_block::{self, IpBlock}};

/// Run query using Diesel to find user by uid and return it.
pub fn find_alert_by_id(
    alert_id: String,
    conn: &SqliteConnection,
) -> Result<Option<models::Alert>, super::DbError> {
    use crate::schema::alerts::dsl::*;

    let alert = alerts
        .filter(id.eq(alert_id))
        .first::<models::Alert>(conn)
        .optional()?;

    Ok(alert)
}

pub fn find_alert_by_page(
    page: i64,
    size: i64,
    source_op: Option<&String>,
    conn: &SqliteConnection,
) -> Result<(Option<Vec<models::Alert>>, i64), super::DbError> {
    use crate::schema::alerts::dsl::*;

    let offset = (page - 1) * size;

    match source_op {
        Some(src) => {
            let alert_vec = alerts
                .filter(solved.eq(false))
                .filter(source.eq(src))
                .order(time.desc())
                .limit(size)
                .offset(offset)
                .load::<models::Alert>(conn)
                .optional()?;
    
            let count = alerts.filter(solved.eq(false)).filter(source.eq(src)).count().get_result::<i64>(conn)?;
        
            Ok((alert_vec, count))
        },
        None => {
            let alert_vec = alerts
                .filter(solved.eq(false))
                .order(time.desc())
                .limit(size)
                .offset(offset)
                .load::<models::Alert>(conn)
                .optional()?;
    
            let count = alerts.filter(solved.eq(false)).count().get_result::<i64>(conn)?;
        
            Ok((alert_vec, count))
        },
    }
    
}

/// Run query using Diesel to insert a new database row and return the result.
pub fn insert_new_alert(
    // prevent collision with `name` column imported inside the function
    new_alert: models::Alert,
    conn: &SqliteConnection,
) -> Result<models::Alert, super::DbError> {
    // It is common when using Diesel with Actix Web to import schema-related
    // modules inside a function's scope (rather than the normal module's scope)
    // to prevent import collisions and namespace pollution.
    use crate::schema::alerts::dsl::*;

    diesel::insert_into(alerts).values(&new_alert).execute(conn)?;

    Ok(new_alert)
}


/// Run query using Diesel to insert a new database row and return the result.
pub fn solve_alert(
    // prevent collision with `name` column imported inside the function
    alert_id: String,
    ip_block: web::Data<ip_block::Iptables>,
    conn: &SqliteConnection,
) -> Result<bool, super::DbError> {
    // It is common when using Diesel with Actix Web to import schema-related
    // modules inside a function's scope (rather than the normal module's scope)
    // to prevent import collisions and namespace pollution.
    // use crate::schema::alerts::dsl::*;

    let alert_op = find_alert_by_id(alert_id, conn)?;
    match alert_op {
        Some(alert) => {
            // 阻断IP
            if alert.mal_obj_type == "IP" {
                ip_block.add_timeout(&alert.mal_obj_key, 1000 * 60 * 10);
            }
            // 杀死进程
            if alert.mal_obj_type == "Process" {
                let pid = alert.mal_obj_key.parse::<i32>().unwrap();
                unsafe {
                    libc::kill(pid, 9);
                }
            }
            // 删除文件
            if alert.mal_obj_type == "File" {
                // TODO 备份文件
                &alert.mal_obj_key;
                // TODO 删除文件
                &alert.mal_obj_key;
            }
        },
        None => (),
    }

    Ok(true)
}